<?php
/**
 * @package html
 */
require_once '_dbobject.php';
require_once '_localemanager.php';
require_once '_img.php';
require_once '_system.php';
require_once '_stringex.php';

/**
 * Classes which implements this interface are used for
 * echoing html code directly into the output.
 * One instance of this class should represent one entity
 * selected from a database.
 */
interface HtmlObject {
	/**
	 * Generate html code, but don't outpu it yet.
	 * @throws Exception - in case of error
	 */
	public function processMe();
	
	/**
	 * Flush html code generated in HtmlObject::processMe
	 * to the output.
	 * The sense of this method is to force programmer to print
	 * generated html code only when it is clear that it will
	 * be printed completely, without any error.
	 * For any html standards won't be offended.
	 */
	public function flushMe();
	
	/**
	 * Method which should group together number of calls of HtmlObject::processMe and HtmlObject::flushMe
	 * in a cycle.
	 */
	public static function init();
}

/**
 * This class stands for one offer selected from the database.
 * There are implemented conjunct methods used across all instances of offers
 * used in different web views.
 */
abstract class HtmlBase implements HtmlObject {
	/**
	 * one entity selected from the database (actually one row)
	 * @var DBObject
	 */
	protected $dbObject; /** @var DBObject */
	/**
	 * buffer which is goning to be filled
	 * @var string
	 */
	protected $buffer; 
	
	/**
	 * Fill HtmlBase::$dbObject structure.
	 * 
	 * @param resource $resource - result from mysql query.
	 * @return DBObject or false in case of failure or empty resource.
	 */
	abstract protected function fetchDbObject(resource $resource);
	
	/**
	 * Fetch one instance of a descendant of this class
	 * carrying one entity which represent one row from the database.
	 * 
	 * @param resource $resource - result from mysql query 
	 * 		(the same will be used in HtmlBase::fetchDbObject)
	 * @return HtmlBase or false
	 */
	abstract static function fetchInstance(resource $resource);
	
	/**
	 * This is a way how HtmlBase::$dbObject won't be empty.
	 */
	public function __construct($resource) {
    	if (!$this->fetchDbObject($resource)) {
    		throw new ExceptionResourceEmpty("resource is empty");
    	}
    }
	
    /**
     * Compare string of picture's $fileName with all possibly generated
     * file names and decide if $fileName was generated automatically or not.
     * 
     * @param string $fileName - file name without path
     * @return bool - Is or isn't generated
     */
	public static function imgIsAlreadyProcessed(string $fileName) {
		return !preg_match("/^" . Policy::imageThumbnailPrefix() . "/", $fileName)
					&& !preg_match("/^" . Policy::imageFullPicThumbViewPrefix() . "/", $fileName)
					&& !preg_match("/^" . Policy::imageThumbPicThumbViewPrefix() . "/", $fileName)
					&& !preg_match("/^" . Policy::imageFullPicPrefix() . "/", $fileName) 
				? false : true;
	}
	
	/**
	 * Flush html code generated in HtmlObject::processMe
	 * to the output.
	 * The sense of this method is to force programmer to print
	 * generated html code only when it is clear that it will
	 * be printed completely, without any error.
	 * For any html standards won't be offended.
	 * 
	 * @see HtmlObject::flushMe
	 */
	public function flushMe() {
		echo $this->buffer;
	}
	
	/**
	 * Replaces templates in the code.
	 * 
	 * @param string $ppatern - perl pattern
	 * @param string $replacement - code to replace with
	 */
	public function replaceTemplate(string $ppattern, $replacement) {
		$this->buffer = preg_replace($ppattern, $replacement , $this->buffer);
	}
	
	/** count of all pages - is the same across all instances */
	protected static $countOfPages;
	/** currently displayed page */
	protected static $currentPage;
	/** url links for other pages */
	protected static $hrefPages;
	/** 
	 * holds count of previous entities which are skipped 
	 * e.g. every page has 20 entities so when you want to display 3rd page
	 * 		this variable equals to 40
	 * 		(this comes from select statement "limit 40, 20")
	 */
	protected static $queryLimit;
	
	/**
	 * Gather all necessary data for creating working pagination.
	 * 
	 * Following class static members are filled:
	 * @see HtmlBase::$countOfPages
	 * @see HtmlBase::$currentPage
	 * @see HtmlBase::$hrefPages
	 * @see HtmlBase::$queryLimit
	 * 
	 * @param int $countInView - desired count of entities on one page
	 * @param string $querySpec - specification of select query
	 * @param string $tableName - name of the table to select from
	 */
	public static function fetchDataForPagesCounting(int $countInView, $querySpec, $tableName = null) {
		$info = SiteContext::getSiteContext();
		$res = $info->getDBConnector()->query("select COUNT(*) from " . $tableName . $querySpec);
		$countOfRows = mysql_fetch_row($res);
		self::$countOfPages = $countOfRows[0] / $countInView;
		self::$countOfPages += $countOfRows[0] % $countInView != 0 ? 1 : 0;
		
		self::$currentPage = (int)@$_GET[Constants::REQ_PAGE];
		if (!is_int(self::$currentPage) || self::$currentPage <= 0 || self::$currentPage > self::$countOfPages) {
			self::$currentPage = 1;
		}
		
		self::$queryLimit = " limit ".(self::$currentPage - 1) * $countInView.", $countInView";
		
		self::$hrefPages = $info->getSiteInf()->urlRelativeWithoutSomeVariables(array(
				Constants::REQ_TYPEOFVIEW => true,
				Constants::REQ_PAGE => true
		));
	}
	
	/** template used in HtmlBase::processImages */
	const _TEMPLATE_THUMBSRC_ = "_TEMPLATE_THUMBSRC_";
	/** template used in HtmlBase::processImages */
	const _TEMPLATE_FULLPICFULLNAME_ = "_TEMPLATE_FULLPICFULLNAME_";
	/** template used in HtmlBase::processImages */
	const _TEMPLATE_MAINIMGSRC_ = "_TEMPLATE_MAINIMGSRC_";
	
	/**
	 * Process images using MultiLangFSDBObject::fetchImgFilename.
	 * Provide $htmlCode which should stand for one picture.
	 * In this $htmlCode followint templates are substituted:
	 * 		HtmlBase::_TEMPLATE_THUMBSRC_ thumbnail web url
	 * 		HtmlBase::_TEMPLATE_FULLPICFULLNAME_ url for full picture of a thumbnail picture
	 * 		HtmlBase::_TEMPLATE_MAINIMGSRC_ url for main img
	 *
	 * @param string $htmlCode
	 * @param function $callback
	 */
	public function processImages(string $htmlCode, $callback = null) {
		$info = SiteContext::getSiteContext();
		$dbObject = $this->dbObject;
		$cm = CodeManager::getCodeManager();
		
		while ($fileName = $dbObject->fetchImgFilename()) {
			/**
			 * Process thumnails.
			 * $filename is not a thumbnail filename AND $filename doesn't begin with prefix ot_
			 * thus thumbnail must be created.
			 */
			if (!$info->getSiteInf()->isThumbnailFileName($fileName) 
					&& !self::imgIsAlreadyProcessed($fileName)) {
				// Looking for thumbnail for this image.
				$fileName = $dbObject->resizePictureIfThereIsNotAlreadyOne($fileName, Policy::imageThumbnailPrefix(), $info->getSiteInf()->imgThumbnailName($fileName), Constants::IMG_THUMBMAXSIZE);
			}
			if ($info->getSiteInf()->isThumbnailFileName($fileName)) {
				$webPath = $info->getSiteInf()->getPathWebImg() . Constants::FS_DIRDELIMITER . $dbObject->imgSubdir();
				$fullPicName = preg_replace("/^" . Policy::imageThumbnailPrefix() . "(.*)" . Policy::imageThumbnailSuffix() . "(\..*)/", Policy::imageFullPicPrefix() . "$1" . Policy::imageFullPicSuffix() . "$2", $fileName);
				$fullPicFullName = "$webPath/$fullPicName";
				$this->buffer .= $htmlCode;
				$this->replaceTemplate("/_TEMPLATE_THUMBSRC_/", $webPath.Constants::FS_DIRDELIMITER.$fileName);
				$this->replaceTemplate("/_TEMPLATE_FULLPICFULLNAME_/", $fullPicFullName);
				if ($callback !== null) {
					$callback($this, $fileName);
				}
			}
			
			/**
			 * Process full pictures.
			 * $filename is not a full picture filename AND $filename doesn't begin with prefix of_
			 * thus fullpic must be created.
			 */
			if (!$info->getSiteInf()->isFullPicFileName($fileName) 
					&& !self::imgIsAlreadyProcessed($fileName)) {
				// Looking for FullPic for this image.
				$fileName = $dbObject->resizePictureIfThereIsNotAlreadyOne($fileName, Policy::imageFullPicPrefix(), $info->getSiteInf()->imgFullPicName($fileName), Constants::IMG_FULLPICMAXSIZE);
			}
			if ($info->getSiteInf()->isFullPicFileName($fileName)) {
				// This actualy happens only for the first time. This will be the main foto.
				$this->replaceTemplate("/_TEMPLATE_MAINIMGSRC_/", $info->getSiteInf()->getPathWebImg() . "/" . $dbObject->imgSubdir() . "/" . $fileName);
			}
		}
	}
	
	/**
	 * Generate html code for one cell of table header.
	 *
	 * @param string $sortVal - replacement
	 * @param unknown_type $columnName - name of column which will be visible in the table
	 * @return string - html code
	 */
	static protected function headerColumn($sortVal, $columnName) {
		$result = '				
						<td>
							<a class="light" href="'.preg_replace("/_TEMPLATESORT_/", $sortVal, self::$href).'">'.$columnName.'</a>
							<a class="up" href="'.preg_replace("/_TEMPLATESORT_/", $sortVal, self::$hrefDesc).'"><img src="/img/spacer.png" width="9px" height="5px" alt="Sort Ascending" /></a>
							<a class="down" href="'.preg_replace("/_TEMPLATESORT_/", $sortVal, self::$hrefAsc).'"><img src="/img/spacer.png" width="9px" height="5px" alt="Sort Descending" /></a>
						</td>';
		return $result;
	}
	
	/**
	 * Map which connects a parameter from an url
	 * with value of order statement of sql query (e.g. SORT ASC | SORT DESC) 
	 */
	protected static $sortTypeMap = array (
		Constants::REQ_SORTTYPE_ASC => "ASC",
		Constants::REQ_SORTTYPE_DESC => "DESC"
	);
	
	/** url to a sortable column used when clicked on a column name */
	static protected $href;
	/** url to sort column in ascending order */
	static protected $hrefAsc;
	/** url to sort column in descending order */
	static protected $hrefDesc;
}
?>